package com.mars.service;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.mars.dao.SysAclMapper;
import com.mars.dao.SysAclModuleMapper;
import com.mars.dao.SysDeptMapper;
import com.mars.dto.AclDto;
import com.mars.dto.AclModuleLevelDto;
import com.mars.dto.DeptLevelDto;
import com.mars.pojo.SysAcl;
import com.mars.pojo.SysAclModule;
import com.mars.pojo.SysDept;
import com.mars.util.LevelUtil;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 *  部门树的计算
 * @author MARS
 * @date 2018/1/3
 */

@Service
public class SysTreeService {

    @Resource
    private SysDeptMapper sysDeptMapper;
    @Resource
    private SysAclModuleMapper sysAclModuleMapper;
    @Resource
    private SysCoreService sysCoreService;
    @Resource
    private SysAclMapper sysAclMapper;
    /**
     * 角色权限树
     *
     */
    public List<AclModuleLevelDto> roleTree(int roleId) {
        // 当前用户已分配的权限点
        List<SysAcl> userAclList = sysCoreService.getCurrentUserAclList();
        // 当前角色已分配的权限点
        List<SysAcl> roleAclList = sysCoreService.getRoleAclList(roleId);
        // 当前系统所有权限点
        List<AclDto> aclDtoList = Lists.newArrayList();

        // 树 java8,lambda语法
        Set<Integer> userAclIdSet  = userAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());
        Set<Integer> roleAclIdSet = roleAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());

        List<SysAcl> allAclList = sysAclMapper.getAll();
        // 获取两者并集(将userAclList合并到roleAclLisr)
        // Set<SysAcl> aclSet = new HashSet<>(allAclList);
        // aclSet.addAll(userAclList);

        for (SysAcl acl : allAclList) {
            // 适配转换为aclDto
            AclDto dto = AclDto.adapt(acl);
            if (userAclIdSet.contains(acl.getId())) {
                // 设置为有权限操作
                dto.setHasAcl(true);
            }

            if (roleAclIdSet.contains(acl.getId())) {
                // 设置为权限选中
                dto.setChecked(true);
            }

            aclDtoList.add(dto);
        }
        return aclListToTree(aclDtoList);
    }

    /**
     * 将set的用户权限和角色权限组装成tree
     * @return
     */
    public List<AclModuleLevelDto> aclListToTree(List<AclDto> aclDtoList) {
        if (CollectionUtils.isEmpty(aclDtoList)) {
            return Lists.newArrayList();
        }

        List<AclModuleLevelDto> aclModuleLevelList = aclModuleTree();

        // 遍历
        Multimap<Integer,AclDto> moduleIdAclMap = ArrayListMultimap.create();
        for (AclDto acl : aclDtoList) {
            // 判断是否可用
            if (acl.getStatus() == 1) {
                moduleIdAclMap.put(acl.getAclModuleId(),acl);
            }
        }
        bindAclsWithOrder(aclModuleLevelList,moduleIdAclMap);
        return aclModuleLevelList;
    }

    /**
     * 权限点绑定到模块树
     */
    public void bindAclsWithOrder(List<AclModuleLevelDto> aclModuleLevelList ,Multimap<Integer,AclDto> moduleIdAclMap) {
        if (CollectionUtils.isEmpty(aclModuleLevelList)) {
            return;
        }

        // 遍历层级
        for (AclModuleLevelDto dto : aclModuleLevelList) {
            List<AclDto> aclDtoList = ( List<AclDto>) moduleIdAclMap.get(dto.getId());
            if (CollectionUtils.isNotEmpty(aclDtoList)) {
                // 排序
                Collections.sort(aclDtoList,aclSeqComparator);
                // 放置到对应的acl
                dto.setAclList(aclDtoList);
            }
            // 对下一层级进行递归绑定
            bindAclsWithOrder(dto.getAclModuleList(),moduleIdAclMap);
        }
    }
    /**
     * 权限模块树
     * @return
     */
    public List<AclModuleLevelDto> aclModuleTree() {
        // 获取当前所有的权限模块
        List<SysAclModule> aclModuleList =  sysAclModuleMapper.getAllAclModule();
        // 先定义权限模块的dto
        List<AclModuleLevelDto> aclModuleLevelDtoList = Lists.newArrayList();
        // 遍历权限模块(将其装载到适配的dto中)
        for (SysAclModule sysAclModule : aclModuleList ) {
            // 每次遍历适配出一个层级结构
            AclModuleLevelDto aclModuleLevelDto = AclModuleLevelDto.adapt(sysAclModule);
            aclModuleLevelDtoList.add(aclModuleLevelDto);
        }

        return aclModuleListToTree(aclModuleLevelDtoList);

    }

    /**
     * 做一个适配权限树
     * @param dtoList
     * @return
     */
    public List<AclModuleLevelDto> aclModuleListToTree(List<AclModuleLevelDto> dtoList) {
        // list是否为空
        if (CollectionUtils.isEmpty(dtoList)) {
            return Lists.newArrayList();
        }
        // multimap( level --> [aclmodule1,aclmodule2,....])
        Multimap<String,AclModuleLevelDto> levelDtoMultimap = ArrayListMultimap.create();
        List<AclModuleLevelDto> rootList = Lists.newArrayList();
        for (AclModuleLevelDto dto : dtoList) {
            levelDtoMultimap.put(dto.getLevel(),dto);
            if (LevelUtil.ROOT.equals(dto.getLevel())) {
                rootList.add(dto);
            }
        }
        // 排序
        Collections.sort(rootList,aclModuleSeqComparator);
        transformAclModuleTree(rootList,LevelUtil.ROOT,levelDtoMultimap) ;
        return rootList;
    }
    /**
     * 权限模块树递归排序
     */
    public void transformAclModuleTree(List<AclModuleLevelDto> aclModuleLevelList,String level,Multimap<String,AclModuleLevelDto> aclModuleLevelMap) {
        for (int i = 0; i < aclModuleLevelList.size(); i++) {
            //遍历该层的每个元素
            AclModuleLevelDto alcModuleLevelDto = aclModuleLevelList.get(i);
            //处理当前层级的数据
            String nextLevel = LevelUtil.calculateLevel(level,alcModuleLevelDto.getId());
            //处理下一层
            List<AclModuleLevelDto> tempAclModuleList = (List<AclModuleLevelDto>)aclModuleLevelMap.get(nextLevel);

            // 判断下层有权限模块
            if (CollectionUtils.isNotEmpty(tempAclModuleList)) {
                //排序
                Collections.sort(tempAclModuleList,aclModuleSeqComparator);
                //设置下一层部门
                alcModuleLevelDto.setAclModuleList(tempAclModuleList);
                //进入到下一层处理
                transformAclModuleTree(tempAclModuleList,nextLevel,aclModuleLevelMap);
            }
        }
    }



    /**
     * 部门树
     * @return
     */
    public List<DeptLevelDto> deptTree(){
        List<SysDept> sysDeptList = sysDeptMapper.getAllDept();

        List<DeptLevelDto> deptLevelDtoList = Lists.newArrayList();
        for(SysDept sysDept : sysDeptList){
            //转换适配树
            DeptLevelDto deptLevelDto = DeptLevelDto.adapt(sysDept);
            deptLevelDtoList.add(deptLevelDto);
        }
        return deptListToTree(deptLevelDtoList);
    }

    /**
     * 做树形结构(将list转换成树)
     */
    public List<DeptLevelDto> deptListToTree(List<DeptLevelDto> deptLevelDtoList){
        // 若为空值，则return 空值
        if (CollectionUtils.isEmpty(deptLevelDtoList)) {
            return Lists.newArrayList();
        }

        // guava中的multimap( level --> [dept1,dept2,....])
        Multimap<String,DeptLevelDto> levelDeptMap = ArrayListMultimap.create();
        // 获取一级部门
        List<DeptLevelDto> rootList = Lists.newArrayList();

        for (DeptLevelDto dto : deptLevelDtoList) {
            levelDeptMap.put(dto.getLevel(),dto);
            if (LevelUtil.ROOT.equals(dto.getLevel())) {
                rootList.add(dto);
            }
        }

        // 按照seq从小到大排序
        Collections.sort(rootList, new Comparator<DeptLevelDto>() {
            @Override
            public int compare(DeptLevelDto o1, DeptLevelDto o2) {
                return o1.getSeq() - o2.getSeq();
            }
        });

        // 递归生成树
        transformDeptTree(rootList,LevelUtil.ROOT,levelDeptMap);
        return rootList;
    }

    /**
     * 部门树递归排序
     */
    public void transformDeptTree(List<DeptLevelDto> deptLevelList,String level,Multimap<String,DeptLevelDto> levelDeptMap) {
        for (int i = 0; i < deptLevelList.size(); i++) {
            //遍历该层的每个元素
            DeptLevelDto deptLevelDto = deptLevelList.get(i);
            //处理当前层级的数据
            String nextLevel = LevelUtil.calculateLevel(level,deptLevelDto.getId());
            //处理下一层
            List<DeptLevelDto> tempDeptList = (List<DeptLevelDto>)levelDeptMap.get(nextLevel);

            if (CollectionUtils.isNotEmpty(tempDeptList)) {
                //排序
                Collections.sort(tempDeptList,deptSeqComparator);
                //设置下一层部门
                deptLevelDto.setDeptList(tempDeptList);
                //进入到下一层处理
                transformDeptTree(tempDeptList,nextLevel,levelDeptMap);
            }
        }
    }

    /**
     * 部门比较器
     */
    public Comparator<DeptLevelDto> deptSeqComparator = new Comparator<DeptLevelDto>() {
        @Override
        public int compare(DeptLevelDto o1, DeptLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };

    /**
     * 权限模块比较器
     */
    public Comparator<AclModuleLevelDto> aclModuleSeqComparator = new Comparator<AclModuleLevelDto>() {
        @Override
        public int compare(AclModuleLevelDto o1, AclModuleLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };

    /**
     * 权限点比较器
     */
    public Comparator<AclDto> aclSeqComparator = new Comparator<AclDto>() {
        @Override
        public int compare(AclDto o1, AclDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };


    /**
     * 获取用户的权限点(获取当前用户已有权限的树)
     * @param userId
     * @return
     */
    public List<AclModuleLevelDto> userAclTree(Integer userId) {

        // 获取核心service
        List<SysAcl> userAclList = sysCoreService.getUserAclList(userId);
        // 转换
        List<AclDto> aclDtoList = Lists.newArrayList();
        for (SysAcl sysAcl : userAclList) {
            // 适配
            AclDto dto = AclDto.adapt(sysAcl);
            dto.setHasAcl(true);
            dto.setChecked(true);
            aclDtoList.add(dto);
        }
        return aclListToTree(aclDtoList);
    }
}